use crate::{code, file, mdb::{self, gridfs::prefix}, query};
use axum::{extract::Query, Json};
use futures_util::io::AsyncReadExt;
use mongodb::options::GridFsBucketOptions;
use serde_json::{json, Value};

use crate::base64;

// 获取文件流
pub async fn get_buffer(objectid:&str, bucket_name:&str, param:&Value) -> Result<Vec<u8>, Json<Value>>{
    let conn = mdb::connect_db_(param).await?;

    let options = GridFsBucketOptions::builder().bucket_name(bucket_name.to_owned()).build();
    let bucket = conn.gridfs_bucket(options);

    let id = mdb::to_object_id(objectid.to_owned());
    let stream = bucket.open_download_stream(id).await;

    match stream {
        Ok(mut f) => {
            let mut buf:Vec<u8> = Vec::new();
            match f.read_to_end(&mut buf).await {
                Ok(_)=> Ok(buf),
                Err(e) => Err(code::sys_(e.to_string()))
            }
        },
        Err(e) => {
            if e.to_string().contains("FileNotFound") {
                Err(code::err_(format!("{objectid} 文件不存在")))
            }else {
                Err(code::sys_(e.to_string()))
            }
        }
    }
}

pub async fn get_base64_op(objectid:&str, bucket_name:&str, param:&Value) -> Result<Option<String>, Json<Value>>{
    let buf = get_buffer(objectid, bucket_name, param).await?;
    Ok(Some(base64::encode(buf)))
}

// 根据上传文件 id 下载载文件
pub async fn download(objectid:&str, bucket:&str, suffix:&str, param:&Value) -> Result<Option<String>, Json<Value>>{
    let url = get_base64_op( &objectid, bucket, param ).await?;
    match url {
        Some(f) => {
            let rs = prefix::get_prefix(suffix)? + &f;
            Ok( Some(rs) )
        },
        None => Ok(None)
    }
}

pub async fn look_by_id_bucket_type(Query(param):Query<Value>) -> Result<Json<Value>, Json<Value>>{
    let id = query::str(&param, "id")?;
    let typ = query::str(&param, "type")?;
    let bucket = query::str(&param, "bucket")?;
    code::data(json!( download(&id, &bucket, &typ, &param).await? ) )
}

// 根据上传文件 id 获取 base64
pub async fn base64(objectid:&str, bucket:&str, param:&Value) -> Result<Option<String>, Json<Value>>{
    let url = get_base64_op( &objectid, bucket, param ).await?;
    match url {
        Some(f) => {
            Ok( Some(f) )
        },
        None => Ok(None)
    }
}
// 查看文件
pub async fn look_by_id(Query(param):Query<Value>) -> Result<Json<Value>, Json<Value>>{
    let id = query::str(&param, "id")?;
    let bucket = query::str(&param, "bucket")?;
    let typ = query::str(&param, "type")?;
    let v = vec!["pdf","png","jpg","png","ico","svg","bmp"];
    let t = &typ[..];
    if v.contains(&t) {
        let rs = base64(&id, &bucket, &param).await?;
        let url = file::download::base64(rs, &id, &typ).await?;
        code::data(json!(url))
    }else{
        code::data(json!( download(&id, &bucket, &typ, &param).await? ) )
    }
}